package cn.tqfeiyang.springplus.generator.jdbc;

import cn.tqfeiyang.springplus.generator.config.GeneratorConfig;
import cn.tqfeiyang.springplus.generator.name.NameConverter;
import cn.tqfeiyang.springplus.generator.name.NameFormat;
import cn.tqfeiyang.springplus.generator.name.NamingStrategy;
import cn.tqfeiyang.springplus.generator.util.Pluralizer;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 关联信息
 *
 * @author tqfeiyang
 * @since 2024/10/7 10:50
 */
@Data
public abstract class JoinInfo {

    /**
     * 生成器配置
     */
    private GeneratorConfig generatorConfig;

    /**
     * 当前表
     */
    private TableInfo thisTable;

    /**
     * 当前字段
     */
    private FieldInfo thisField;

    /**
     * 关联表
     */
    private TableInfo joinTable;

    /**
     * 关联字段
     */
    private FieldInfo joinField;

    /**
     * 注释
     */
    private String comment;

    /**
     * 获取关联类型
     *
     * @return 关联类型
     */
    public abstract String getJoinType();

    /**
     * 反向的关联
     */
    private JoinInfo reverseJoin;

    /**
     * 获取反向关联对象
     *
     * @return 反向关联
     */
    public JoinInfo getReverseJoin() {
        if (Objects.isNull(reverseJoin)) {
            reverseJoin = handleReverse();
        }
        return reverseJoin;
    }

    protected abstract JoinInfo handleReverse();

    public Map<String, String> getNf() {
        Map<String, String> map = new HashMap<>();
        NameConverter nameConverter = getGeneratorConfig().getNameConverter();
//        map.put("joinListMethod", String.format("get%sList",
//                nameConverter.convert(getJoinTable(), NameFormat.EntityName)));
//        map.put("joinInfoMethod", String.format("get%sInfo",
//                nameConverter.convert(getJoinTable(), NameFormat.EntityName)));

//        map.put("joinCountMethod", String.format("countOf%s",
//                Pluralizer.toPlural(nameConverter.convert(getJoinTable(), NameFormat.EntityName))));

        map.put("countMethod", String.format("countOf%s",
                Pluralizer.toPlural(nameConverter.convert(getJoinTable(), NameFormat.EntityName)),
                NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
        map.put("queryListMethod", String.format("query%s",
                Pluralizer.toPlural(nameConverter.convert(getJoinTable(), NameFormat.EntityName)),
                NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
        map.put("selectListMethod", String.format("select%s",
                Pluralizer.toPlural(nameConverter.convert(getJoinTable(), NameFormat.EntityName)),
                NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));

        if (this instanceof OneToManyJoin || this instanceof ManyToManyJoin) {
            map.put("joinVariableName", String.format("%sList",
                    nameConverter.convert(getJoinTable(), NameFormat.VariableName)));
        } else {
            map.put("joinVariableName", String.format("%s",
                    nameConverter.convert(getJoinTable(), NameFormat.VariableName)));
        }
        map.put("joinSetterMethod", String.format("set%s",
                NamingStrategy.capitalFirst(map.get("joinVariableName"))));
        map.put("joinGetterMethod", String.format("get%s",
                NamingStrategy.capitalFirst(map.get("joinVariableName"))));

        return map;
    }

    /**
     * 多对一关联
     */
    @Data
    public static class ManyToOneJoin extends JoinInfo {
        @Override
        public String getJoinType() {
            return "m2o";
        }

        @Override
        protected JoinInfo handleReverse() {
            OneToManyJoin oneToManyJoin = new OneToManyJoin();
            oneToManyJoin.setThisTable(this.getJoinTable());
            oneToManyJoin.setThisField(this.getJoinField());
            oneToManyJoin.setJoinTable(this.getThisTable());
            oneToManyJoin.setJoinField(this.getThisField());
            oneToManyJoin.setComment(this.getJoinField().getComment().toLowerCase().replace("id", ""));
            oneToManyJoin.setReverseJoin(this);
            return oneToManyJoin;
        }
    }

    /**
     * 一对多关联
     */
    @Data
    public static class OneToManyJoin extends JoinInfo {
        @Override
        public String getJoinType() {
            return "o2m";
        }

        @Override
        protected JoinInfo handleReverse() {
            ManyToOneJoin manyToOneJoin = new ManyToOneJoin();
            manyToOneJoin.setThisTable(this.getJoinTable());
            manyToOneJoin.setThisField(this.getJoinField());
            manyToOneJoin.setJoinTable(this.getThisTable());
            manyToOneJoin.setJoinField(this.getThisField());
            manyToOneJoin.setComment(this.getJoinField().getComment().toLowerCase().replace("id", ""));
            manyToOneJoin.setReverseJoin(this);
            return manyToOneJoin;
        }
    }

    /**
     * 多对多关联
     */
    @Data
    public static class ManyToManyJoin extends JoinInfo {
        /**
         * 交叉信息
         */
        public CrossInfo getCrossInfo() {
            return crossTable.getCrossInfo();
        }

        /**
         * 交叉表
         */
        private TableInfo crossTable;

        /**
         * 交叉表当前字段
         */
        private FieldInfo crossThisField;

        /**
         * 交叉表关联字段
         */
        private FieldInfo crossJoinField;

        @Override
        public String getJoinType() {
            return "m2m";
        }

        @Override
        protected JoinInfo handleReverse() {
            ManyToManyJoin manyToOneJoin = new ManyToManyJoin();
            manyToOneJoin.setThisTable(this.getJoinTable());
            manyToOneJoin.setThisField(this.getJoinField());
            manyToOneJoin.setJoinTable(this.getThisTable());
            manyToOneJoin.setJoinField(this.getThisField());
            manyToOneJoin.setComment(this.getJoinField().getComment().toLowerCase().replace("id", ""));
            manyToOneJoin.setReverseJoin(this);

            manyToOneJoin.setCrossTable(this.getCrossTable());
            manyToOneJoin.setCrossThisField(this.getCrossJoinField());
            manyToOneJoin.setCrossJoinField(this.getCrossThisField());

            return manyToOneJoin;
        }

        @Override
        public Map<String, String> getNf() {
            Map<String, String> map = super.getNf();
            NameConverter nameConverter = getGeneratorConfig().getNameConverter();
//            map.put("joinCountMethod", String.format("countOf%sBy%s",
//                    Pluralizer.toPlural(nameConverter.convert(getJoinTable(), NameFormat.EntityName)),
//                    NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
//            map.put("queryListMethod", String.format("query%sBy%s",
//                    Pluralizer.toPlural(nameConverter.convert(getJoinTable(), NameFormat.EntityName)),
//                    NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
//            map.put("getListMethod", String.format("get%sBy%s",
//                    Pluralizer.toPlural(nameConverter.convert(getJoinTable(), NameFormat.EntityName)),
//                    NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
            map.put("selectIdsMethod", String.format("select%s",
                    NamingStrategy.capitalFirst(nameConverter.convert(getJoinField(), NameFormat.PluralPropertyName)),
                    NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
            map.put("assignIdsMethod", String.format("assign%s",
                    NamingStrategy.capitalFirst(nameConverter.convert(getJoinField(), NameFormat.PluralPropertyName)),
                    NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
            map.put("unassignIdsMethod", String.format("delete%s",
                    NamingStrategy.capitalFirst(nameConverter.convert(getJoinField(), NameFormat.PluralPropertyName)),
                    NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
            map.put("clearIdsMethod", String.format("deleteAll%s",
                    NamingStrategy.capitalFirst(nameConverter.convert(getJoinField(), NameFormat.PluralPropertyName)),
                    NamingStrategy.capitalFirst(nameConverter.convert(getThisField(), NameFormat.PropertyName))));
            return map;
        }
    }
}
